﻿using S7Cat.Enums;
using S7Cat.Tools;
using System.Net.Sockets;

namespace S7Cat.Protocol
{
    internal record TPDU
    {
        public bool IsLastUnit { get; set; }
        public PduType PduType { get; set; }
        public MemoryOwner<byte> Data { get; set; }

        private TPDU(MemoryOwner<byte> tpktData)
        {
            var span = tpktData.Span;
            var headerLen = span[0];
            if (headerLen >= 2)
            {
                PduType = (PduType)span[1];
                if (PduType == PduType.Data)
                {
                    var flags = span[2];
                    //var TPDUNumber = flags & 0x7F;
                    IsLastUnit = (flags & 0x80) > 0;

                    Data = tpktData.Slice(headerLen + 1, tpktData.Length - headerLen - 1);
                }
                else
                {
                    Data = MemoryOwner<byte>.Empty;
                }
            }
            else
            {
                Data = MemoryOwner<byte>.Empty;
            }
        }

        public static async Task<TPDU> ReadAsync(NetworkStream stream, CancellationToken cancellationToken)
        {
            using var tpktData = await TPKT.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
            return tpktData.Length == 0 ? throw new Exception("No protocol data received") : new TPDU(tpktData);
        }

        public static async Task<(MemoryOwner<byte>, bool)> ReadDataAsync(NetworkStream stream, CancellationToken cancellationToken)
        {
            using var tpktData = await TPKT.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
            if (tpktData.Length == 0)
            {
                throw new Exception("No protocol data received");
            }

            var isLastUnit = false;
            var data = MemoryOwner<byte>.Empty;

            var span = tpktData.Span;
            var headerLen = span[0];
            if (headerLen >= 2)
            {
                if ((PduType)span[1] == PduType.Data)
                {
                    var flags = span[2];
                    isLastUnit = (flags & 0x80) > 0;

                    data = tpktData.Slice(headerLen + 1, tpktData.Length - headerLen - 1);
                }
            }

            return (data, isLastUnit);
        }
    }
}
